package com.changgou.seckill.web.aspect;

import com.alibaba.fastjson.JSON;
import com.changgou.entity.Result;
import com.changgou.entity.StatusCode;
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * @author kfzhao
 * @version 1.0
 * @className AccessLimitAop
 * @description
 * @date 2022/1/7 2:48
 */
@Component
@Scope
@Aspect
public class AccessLimitAop {

    @Autowired
    private HttpServletResponse response;

    // 设置令牌生成速率

    // 每秒生成2个令牌存入桶中
    private RateLimiter rateLimiter = RateLimiter.create(2.0);

    /**
     * 配置限流的增强方法与切点
     *
     * @param
     * @return void
     * @throws
     * @description
     * @author kfzhao
     * @date 2022/1/7 2:51
     */
    @Pointcut("@annotation(com.changgou.seckill.web.aspect.AccessLimit)")
    public void limit() {

    }

    /**
     * 环绕增强的方法
     *
     * @param proceedingJoinPoint
     * @return java.lang.Object
     * @throws
     * @description
     * @author kfzhao
     * @date 2022/1/7 2:52
     */
    @Around("limit()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        boolean flag = rateLimiter.tryAcquire();
        // 当前方法的返回值
        Object obj = null;
        if (flag) {
            // 现在允许访问
            try {
                obj = proceedingJoinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        } else {
            // 不允许访问
            String errorMessage = JSON.toJSONString(new Result<>(false, StatusCode.ACCESSERROR, "fail"));
            // 将信息返回到客户端
            outMessage(response, errorMessage);
        }
        return obj;
    }

    /**
     * 对客户端返回信息
     *
     * @param response
     * @param errorMessage
     * @return void
     * @throws
     * @description
     * @author kfzhao
     * @date 2022/1/7 2:55
     */
    private void outMessage(HttpServletResponse response, String errorMessage) {
        ServletOutputStream outputStream = null;
        try {
            response.setContentType("application/json;charset=utf-8");
            outputStream = response.getOutputStream();
            outputStream.write(errorMessage.getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
